feat(frontend): typed API client generated from the OpenAPI spec + gen-verify CI#59
feat(frontend): typed API client generated from the OpenAPI spec + gen-verify CI#59AgentWrapper wants to merge 1 commit into
Conversation
Greptile SummaryThis PR introduces a typed
Confidence Score: 4/5Safe to merge with one fix: the hardcoded daemon port needs to be read from the runfile before the client is wired up to real callers. The client hardcodes http://127.0.0.1:3001 but the runfile package was explicitly designed to publish the daemon's actual bound port to the Electron main process — if 3001 is occupied and the daemon binds elsewhere, every API call will target a dead address. The CI job and the generated schema are clean. frontend/src/api/client.ts — the baseUrl should derive the port from the runfile rather than hardcoding 3001. Important Files Changed
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant Go as Go Backend
participant Spec as openapi.yaml
participant TS as schema.d.ts
participant CI as gen-verify CI
Dev->>Go: modify contract type
Dev->>Go: go generate ./...
Go->>Spec: regenerate openapi.yaml
Dev->>TS: npm run gen:api
Spec->>TS: regenerate schema.d.ts
Dev->>CI: push / open PR
CI->>Go: go generate ./...
Go->>Spec: regenerate openapi.yaml
CI->>TS: npm run gen:api
Spec->>TS: regenerate schema.d.ts
CI->>CI: git diff --exit-code
alt committed files match regenerated output
CI-->>Dev: pass
else committed files are stale
CI-->>Dev: fail — regenerate and commit
end
Reviews (5): Last reviewed commit: "feat(frontend): typed API client generat..." | Re-trigger Greptile |
…chema names Resolve the four review comments on #59: - ProjectOrDegraded.MarshalJSON now errors when neither Project nor Degraded is set instead of silently emitting `{"project": null}`, which would breach the required oneOf[Project, Degraded] contract. - requestBody.required: true is now set for addProject and updateProjectConfig via WithCustomize — swaggest left it absent (== optional) before. - schemaName replaces the TrimPrefix catch-all with an exhaustive default→clean map; an unrecognised type is returned verbatim so it surfaces in the diff rather than silently colliding with an existing schema. - nonNullableSlices strips the spurious "null" swaggest unions into every Go slice, so `projects` is `Summary[]` not `Summary[] | null`; the list handler normalises a nil slice to [] so the wire matches the non-nullable schema. Regenerated openapi.yaml + frontend schema.d.ts. Refs #59.
0de7ce0 to
49c7883
Compare
Addresses the P1 follow-up on #59: returning an error from ProjectOrDegraded.MarshalJSON does not "surface" the contract violation — envelope.WriteJSON discards the encode error after the 200 status and a partial JSON frame have already been flushed, leaving the client with a truncated, unparseable 200 (worse than the previous null). Validate the invariant upstream instead: newGetProjectResponse now returns an error when the GetResult sets neither Project nor Degraded, and the get handler maps that to a 500 envelope before any status/body is written. MarshalJSON keeps the error branch only as an unreachable last-resort backstop, with the comment corrected to say so. Adds TestProjectsAPI_GetEmptyResultIs500 to lock the clean-500 behavior. Refs #59.
…penAPI
- Remove POST /reload, PATCH /{id}, POST /{id}/repair routes and their
Manager methods (Reload, UpdateConfig, Repair) and DTOs (ReloadResult,
UpdateConfigInput) — not needed at this stage
- Merge Manager interface into manager.go; delete project.go (single-impl
split served no purpose)
- Remove dead notImplemented helper from errors.go
- Port PR #59 code-first OpenAPI generation: controllers/dto.go named
response types, specgen/build.go (4 routes), parity + drift tests,
cmd/genspec, go generate wiring; regenerate openapi.yaml
- Add swaggest deps; add YAML() method to apispec.Spec
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…chema names Resolve the four review comments on #59: - ProjectOrDegraded.MarshalJSON now errors when neither Project nor Degraded is set instead of silently emitting `{"project": null}`, which would breach the required oneOf[Project, Degraded] contract. - requestBody.required: true is now set for addProject and updateProjectConfig via WithCustomize — swaggest left it absent (== optional) before. - schemaName replaces the TrimPrefix catch-all with an exhaustive default→clean map; an unrecognised type is returned verbatim so it surfaces in the diff rather than silently colliding with an existing schema. - nonNullableSlices strips the spurious "null" swaggest unions into every Go slice, so `projects` is `Summary[]` not `Summary[] | null`; the list handler normalises a nil slice to [] so the wire matches the non-nullable schema. Regenerated openapi.yaml + frontend schema.d.ts. Refs #59.
Addresses the P1 follow-up on #59: returning an error from ProjectOrDegraded.MarshalJSON does not "surface" the contract violation — envelope.WriteJSON discards the encode error after the 200 status and a partial JSON frame have already been flushed, leaving the client with a truncated, unparseable 200 (worse than the previous null). Validate the invariant upstream instead: newGetProjectResponse now returns an error when the GetResult sets neither Project nor Degraded, and the get handler maps that to a 500 envelope before any status/body is written. MarshalJSON keeps the error branch only as an unreachable last-resort backstop, with the comment corrected to say so. Adds TestProjectsAPI_GetEmptyResultIs500 to lock the clean-500 behavior. Refs #59.
63f5daa to
4645ab9
Compare
…penAPI
- Remove POST /reload, PATCH /{id}, POST /{id}/repair routes and their
Manager methods (Reload, UpdateConfig, Repair) and DTOs (ReloadResult,
UpdateConfigInput) — not needed at this stage
- Merge Manager interface into manager.go; delete project.go (single-impl
split served no purpose)
- Remove dead notImplemented helper from errors.go
- Port PR #59 code-first OpenAPI generation: controllers/dto.go named
response types, specgen/build.go (4 routes), parity + drift tests,
cmd/genspec, go generate wiring; regenerate openapi.yaml
- Add swaggest deps; add YAML() method to apispec.Spec
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* refactor(project): manager talks to the sqlite store; drop the in-memory store The project Manager now runs only against the durable backend store: remove the process-local MemoryStore (and NewMemoryManager), and require a real Store. The daemon already wires the sqlite store; tests now build a real temp-dir sqlite store instead of the mock. - Move Row + the Store port to project/store.go. The Store interface stays because it is the dependency-inversion port that lets the manager reach the backend without an import cycle (storage imports project.Row), not an extra mock layer — there is no longer any in-memory implementation. - NewManager requires a non-nil Store (no in-memory fallback). - Add project/manager_test.go: List/Add/Get/Remove happy paths + PATH_REQUIRED/NOT_A_GIT_REPO/PATH_ALREADY_REGISTERED/ID_ALREADY_REGISTERED, PROJECT_NOT_FOUND/INVALID_PROJECT_ID, and UpdateConfig — all against a real sqlite store (the service-logic tests #47 lacked). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(project): trim routes, consolidate package, add code-first OpenAPI - Remove POST /reload, PATCH /{id}, POST /{id}/repair routes and their Manager methods (Reload, UpdateConfig, Repair) and DTOs (ReloadResult, UpdateConfigInput) — not needed at this stage - Merge Manager interface into manager.go; delete project.go (single-impl split served no purpose) - Remove dead notImplemented helper from errors.go - Port PR #59 code-first OpenAPI generation: controllers/dto.go named response types, specgen/build.go (4 routes), parity + drift tests, cmd/genspec, go generate wiring; regenerate openapi.yaml - Add swaggest deps; add YAML() method to apispec.Spec Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fix(project): address PR review comments - t.Skipf → t.Fatalf in gitRepo helper: git failures now hard-fail instead of silently skipping manager tests on a misconfigured runner - FindProjectByPath: add AND archived_at IS NULL so archived paths don't permanently block re-registration (update queries/projects.sql and generated gen/projects.sql.go) - Add TestManager_ReaddAfterRemove to lock the fix Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fixed lint and fmt * addressed greptile comments * Apply suggestions from code review Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * project tests fix * project_tests fix * fix: Linting and formatting fix * refactor: move project manager into service layer (#68) * refactor: split service package by resource (#68) * fix: ignore archived project id conflicts (#68) * refactor: move pr manager into service layer (#68) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: itrytoohard <ayetrytoohard@gmail.com>
55e4f5e to
064c188
Compare
…n-verify CI The code-first OpenAPI generator landed on main (covering projects + sessions), superseding this branch's backend work. This repurposes the PR to the parts main still lacks: - frontend/src/api/schema.d.ts — generated from backend/internal/httpd/apispec/ openapi.yaml via openapi-typescript (`npm run gen:api`); covers projects, sessions, and orchestrators. - frontend/src/api/client.ts — a small openapi-fetch client typed by that schema, so the renderer's request/response types come from the daemon contract instead of being hand-maintained. - CI gen-verify job — regenerates the spec from Go and the TS client from the spec, failing if either committed artifact is stale. Backend drift is also covered by the apispec tests; this additionally guards the frontend artifact, which nothing else checks. Frontend typecheck passes; the gen pipeline reproduces the committed files with no drift.
064c188 to
019c985
Compare
Why (scope change)
This PR originally added the code-first OpenAPI generator + a frontend client. The backend generator has since landed on
main(via #68/#65) and now covers projects and sessions — superseding this branch's backend work. Rather than duplicate it, this PR is repurposed to the partsmainstill lacks.What's here
frontend/src/api/schema.d.ts— generated frombackend/internal/httpd/apispec/openapi.yamlviaopenapi-typescript(npm run gen:api). Covers projects, sessions, and orchestrators.frontend/src/api/client.ts— a smallopenapi-fetchclient typed by that schema, so the renderer's request/response types come from the daemon contract instead of being hand-maintained.gen-verifyCI job — regenerates the spec from Go and the TS client from the spec, failing if either committed artifact is stale. Backend drift is already covered by theapispectests; this additionally guards the frontend artifact, which nothing else checks.Verification
Rebased on current
main; no overlap with the backend codegen or the recent CLI PRs.🤖 Generated with Claude Code